from cProfile import label

import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
import matplotlib.lines as lines
import numpy as np


def data_generate(filename):
    fr = open(filename, 'r')
    lines = fr.readlines()
    linesNum = len(lines)
    Matrix = np.zeros((linesNum, 14))
    labels = []
    for (i, line) in enumerate(lines):
        line = line.strip()
        line_data = line.split(',')
        Matrix[i, :] = line_data[0:14]
    np.random.shuffle(Matrix)
    labels = Matrix[:, 0]
    dataMatrix = Matrix[:, 1:14]
    return dataMatrix, labels


def data_normalization(dataMatrix):
    mins = dataMatrix.min(0)
    maxs = dataMatrix.max(0)
    ranges = maxs - mins
    matNormalized = np.zeros(np.shape(dataMatrix))
    m = dataMatrix.shape[0]
    matNormalized = dataMatrix - np.tile(mins, (m, 1))
    matNormalized = matNormalized / np.tile(mins, (m, 1))
    testUnit = mins
    trainingSet = matNormalized
    return trainingSet, ranges, testUnit


def unitclassify(testUnit, trainingSet, labels, k):
    traingSetSize = trainingSet.shape[0]
    diffMatrix = np.tile(testUnit, (traingSetSize, 1)) - trainingSet
    sqMatrix = diffMatrix ** 2
    distanceMatrix = sqMatrix.sum(axis=1)
    distance = distanceMatrix ** 0.5
    sortedLabels = distance.argsort()
    classCountDict = {}
    for i in range(k):
        label = labels[sortedLabels[i]]
        classCountDict[label] = classCountDict.get(label, 0) + 1
    sortedClassCountDict = sorted(classCountDict.items(), key=lambda unit: unit[1], reverse=True)
    return sortedClassCountDict[0][0]


def model_test():
    filename = "wine.data"
    Matrix, labels = data_generate(filename)
    # showdatas(Matrix,labels)
    randomRatio = 0.10
    matNormalized, ranges, mins = data_normalization(Matrix)
    m = matNormalized.shape[0]
    numTest = int(m * randomRatio)
    correctCount = 0.0
    for i in range(numTest):
        result = unitclassify(matNormalized[i, :],
                              matNormalized[numTest:m, :],
                              labels[numTest:m], 5)
        print("预测类别:%s\t真实类别:%s" % (result, labels[i]))
        if result == labels[i]:
            correctCount += 1.0
    print("正确率:%.2f%%" % (correctCount / float(numTest) * 100))


# 15-9 数据输入预测函数
def sample_test():
    """
    对所有测试集数据进行分类，检验分类器正确率
    """
    property1 = float(input("1 请输入酒精的值:(Alcohol):一般范围大致在 11 - 15%(体积分数)左右。"))
    property2 = float(input("2 请输入苹果酸的值:(Malic acid):含量通常在 0 - 6g/L 之间。"))
    property3 = float(input("3 请输入灰分的值:(Ash):其值大约在 1.3 - 3g/L。"))
    property4 = float(input("4 请输入灰分的碱度的值:(Alcalinity of ash):范围大概是 10 - 30mg/L。"))
    property5 = float(input("5 请输入镁的值:(Magnesium):含量一般在 70 - 160mg/L。"))
    property6 = float(input("6 请输入总酚类的值:(Total phenols):大致范围是 0 - 5g/L。"))
    property7 = float(input("7 请输入类黄酮的值:(Flavanoids):通常在 0 - 5g/L。"))
    property8 = float(input("8 请输入非类黄酮酚类的值:(Nonflavanoid phenols):含量可能在 0 - 3g/L。"))
    property9 = float(input("9 请输入原花青素的值:(Proanthocyanins):一般在 0 - 5g/L。"))
    property10 = float(input("10 请输入颜色强度的值:(Color intensity):范围大约是 1 - 13。"))
    property11 = float(input("11 请输入色调的值:(Hue):数值大概在 0.4 - 1.7 左右。"))
    property12 = float(input("12 请输入OD280/OD315 of diluted wines的值:"
                             "(稀释葡萄酒在 280nm 和 315nm 处的吸光度比值):一般在 1 - 4 之间。"))
    property13 = float(input("13 请输入脯氨酸的值:(Proline):含量可能在 200 - 1600mg/L。"))

    filename = "wine.data"
    Matrix, labels = data_generate(filename)
    matNormalized, ranges, mins = data_normalization(Matrix)

    # 规范创建testUnit数组
    testUnit = np.array([property1, property2, property3, property4, property5,
                         property6, property7, property8, property9, property10,
                         property11, property12, property13])

    testUnit_normalized = (testUnit - mins) / ranges
    # print(testUnit_normalized)
    result = unitclassify(testUnit_normalized, matNormalized, labels, 5)
    print(f"这可能是第{result}类酒")


def showdatas(dataMatrix, labels):
    fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(13, 8))
    font = FontProperties()
    font.set_family('SimHei')  # 设置字体
    font.set_size(9)  # 设置字号
    font.set_weight('bold')  # 加粗
    colors = []
    for i in labels:
        if i == 1:
            colors.append('black')  # 类型1颜色为黑
        elif i == 2:
            colors.append('red')  # 类型2颜色为红
        elif i == 3:
            colors.append('blue')  # 类型3颜色为蓝
    markers = []
    for i in labels:
        if i == 1:
            markers.append('o')  # 类型1形状为圆
        elif i == 2:
            markers.append('^')  # 类型形状为上三角
        elif i == 3:
            markers.append('x')  # 类型3形状为x

    # 用循环好绘制每一个点的形状及颜色
    for i in range(len(dataMatrix)):
        axs[0][0].scatter(dataMatrix[i, 0], dataMatrix[i, 1], marker=markers[i], color=colors[i], s=15, alpha=1)
        axs[0][1].scatter(dataMatrix[i, 2], dataMatrix[i, 3], marker=markers[i], color=colors[i], s=15, alpha=1)
        axs[1][0].scatter(dataMatrix[i, 4], dataMatrix[i, 5], marker=markers[i], color=colors[i], s=15, alpha=1)
        axs[1][1].scatter(dataMatrix[i, 6], dataMatrix[i, 7], marker=markers[i], color=colors[i], s=15, alpha=1)
    # 设置标题
    axs[0][0].set_title('Alcohol and Malic acid', color='black', fontproperties=font)
    axs[0][0].set_xlabel('Alcohol', color='black', fontproperties=font)
    axs[0][0].set_ylabel('Malic acid', color='black', fontproperties=font)

    axs[0][1].set_title('Ash and Alkalinity of ash', color='black', fontproperties=font)
    axs[0][1].set_xlabel('Ash', color='black', fontproperties=font)
    axs[0][1].set_ylabel('Alkalinity of ash', color='black', fontproperties=font)

    axs[1][0].set_title('Magnesium and Total phenols', color='black', fontproperties=font)
    axs[1][0].set_xlabel('Magnesium', color='black', fontproperties=font)
    axs[1][0].set_ylabel('Total phenols', color='black', fontproperties=font)

    axs[1][1].set_title('Flavonoids and Nonflavonoid phenols', color='black', fontproperties=font)
    axs[1][1].set_xlabel('Flavonoids', color='black', fontproperties=font)
    axs[1][1].set_ylabel('Nonflavonoid phenols', color='black', fontproperties=font)

    class1 = lines.Line2D([], [], color='black', marker='o', markersize=6, label='1')
    class2 = lines.Line2D([], [], color='red', marker='^', markersize=6, label='2')
    class3 = lines.Line2D([], [], color='blue', marker='x', markersize=6, label='3')

    axs[0][0].legend(handles=[class1, class2, class3])
    axs[0][1].legend(handles=[class1, class2, class3])
    axs[1][0].legend(handles=[class1, class2, class3])
    axs[1][1].legend(handles=[class1, class2, class3])

    plt.show()


if __name__ == "__main__":
    filename = "./data/wine.data"
    dataMatrix, labels = data_generate(filename)
    trainingSet, ranges, testUnit = data_normalization(dataMatrix)
    k = 5
    sortedClassCountDict = unitclassify(testUnit, trainingSet, labels, k)
    print(f"预测分类结果:{sortedClassCountDict}")
    # modelTest()
    # sampleTest()
    showdatas(dataMatrix, labels)
